﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Collections.Specialized;
using System.Reflection;

namespace MyLibrary.Text.JSON.Utility
{
    public class JSONUtils
    {
        public static string Enquote(string s)
        {
            if (String.IsNullOrEmpty(s)) return "\"\"";

            char c; int i; int length = s.Length;
            string t;
            StringBuilder sb = new StringBuilder(length + 4);

            sb.Append('"');
            for (i = 0; i < length; i++)
            {
                c = s[i];
                if (c == '\\' || c == '"' || c == '>')
                    sb.Append('\\').Append(c);
                else if (c == '\b')
                    sb.Append("\\b");
                else if (c == '\t')
                    sb.Append("\\t");
                else if (c == '\n')
                    sb.Append("\\n");
                else if (c == '\f')
                    sb.Append("\\f");
                else if (c == '\r')
                    sb.Append("\\r");
                else
                {
                    if (c == ' ')
                    {
                        string tmp = new string(c, 1);
                        t = "000" + int.Parse(tmp, NumberStyles.HexNumber);
                        sb.Append("\\u" + t.Substring(t.Length - 4));
                    }
                    else
                        sb.Append(c);
                }
            }
            sb.Append('"');
            return sb.ToString();
        }
    }
    public class JSONTokener
    {
        #region 属性
        private int _index;

        public int Index
        {
            get { return _index; }
            set { _index = value; }
        }
        private string _source;

        public string Source
        {
            get { return _source; }
            set { _source = value; }
        }

        public JSONTokener(string source)
        {
            this._index = 0;
            this._source = source;
        }
        #endregion

        #region 静态方法
        public static int DehexChar(char c)
        {
            if (c >= '0' && c <= '9')
                return c - '0';
            else if (c >= 'A' && c <= 'F')
                return c + 10 - 'A';
            else if (c >= 'a' && c <= 'f')
                return c + 10 - 'a';
            else
                return -1;
        }
        public static string Unescape(string s)
        {
            int len = s.Length;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < len; i++)
            {
                char c = s[i];
                if (c == '+')
                    c = ' ';
                else if (c == '%' && (i + 2 < len))
                {
                    int d = DehexChar(s[i + 1]);
                    int e = DehexChar(s[i + 2]);
                    if (d >= 0 && e >= 0)
                    {
                        c = (char)(d * 16 + e);
                        i += 2;
                    }
                }
                sb.Append(c);
            }
            return sb.ToString();
        }
        #endregion

        #region 公有方法
        public char GetNextChar()
        {
            char c = _index < _source.Length ? _source[_index] : (char)0;
            _index++;
            return c;
        }
        public char GetNextChar(char c)
        {
            char n = GetNextChar();
            if (n != c)
                throw new Exception("Excepted '" + c + "' and instead saw '" + n + ".");
            return n;
        }
        public string GetNextChar(int count)
        {
            int offset = _index + count;
            if (offset > _source.Length)
                throw new OverflowException("数组超出界限");

            _index += count;
            return _source.Substring((_index - count), count);
        }
        public char GetNextCharClean()
        {
            while (true)
            {
                char c = GetNextChar();
                if (c == '/')
                {
                    c = GetNextChar();
                    if (c == '/')
                    {
                        do
                        {
                            c = GetNextChar();
                        } while (c != '\n' && c != '\r' && c != 0);
                    }
                    else if (c == '*')
                    {
                        while (true)
                        {
                            c = GetNextChar();
                            if (c == 0)
                                throw new FormatException("未闭合的注释");
                            if (c == '*')
                            {
                                if (GetNextChar() == '/')
                                    break;
                                _index -= 1;
                            }
                        }
                    }
                    else
                    {
                        _index -= 1;
                        return '/';
                    }
                }
                else if (c == 0 || c > ' ')
                    return c;
            }
        }
        public string GetNextString(char quote)
        {
            char c;
            StringBuilder sb = new StringBuilder();

            while (true)
            {
                c = GetNextChar();
                if (c == 0x00 || c == 0x0A || c == 0x0D) throw new FormatException("为完结的字符串");

                if (c == '\\')
                {
                    c = GetNextChar();
                    switch (c)
                    {
                        case 'b':
                            sb.Append('\b');
                            break;
                        case 't':
                            sb.Append('\t');
                            break;
                        case 'n':
                            sb.Append('\n');
                            break;
                        case 'f':
                            sb.Append('\f');
                            break;
                        case 'r':
                            sb.Append('\r');
                            break;
                        case 'u':
                            int iascii = int.Parse(GetNextChar(4), NumberStyles.HexNumber);
                            sb.Append((char)iascii);
                            break;
                        default:
                            sb.Append(c);
                            break;
                    }
                }
                else
                {
                    if (c == quote)
                        return sb.ToString();
                    sb.Append(c);
                }
            }
        }
        public string GetNextTo(char d)
        {
            StringBuilder sb = new StringBuilder();
            while (true)
            {
                char c = GetNextChar();
                if (c == d || c == 0x00 || c == 0x0A || c == 0x0D)
                {
                    if (c != 0x00) _index -= 1;
                    return sb.ToString().Trim();
                }
                sb.Append(c);
            }
        }
        public string GetNextTo(string delimiters)
        {
            char c;
            StringBuilder sb = new StringBuilder();
            while (true)
            {
                c = GetNextChar();
                if (c == 0x00 || c == 0x0A || c == 0x0D || delimiters.IndexOf(c) >= 0)
                {
                    if (c != 0x00)
                        _index -= 1;
                    return sb.ToString().Trim();
                }
                sb.Append(c);
            }
        }
        public object GetNextObject()
        {
            char c = GetNextCharClean();
            string s = String.Empty;

            if (c == '"' || c == '\'') return GetNextString(c);
            //Object
            if (c == '{')
            {
                _index -= 1;
                // return new JSONObject(this);
            }
            //Array
            if (c == '[')
            {
                _index -= 1;
                // return new JSONArray(this);
            }

            StringBuilder sb = new StringBuilder();
            char b = c;
            while (c >= ' ' && c != ':' && c != ',' && c != ']' && c != '}' && c != '/')
            {
                sb.Append(c);
                c = GetNextChar();
            }
            _index -= 1;

            s = sb.ToString().Trim();
            if (s == "true")
                return true;
            if (s == "false")
                return false;
            if (s == "null")
                return "null";

            if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+')
            {
                try
                {
                    return Convert.ToInt32(s);
                }
                catch
                {
                    //Eat     
                }
                try
                {
                    return Convert.ToDouble(s, NumberFormatInfo.InvariantInfo);
                }
                catch
                {
                    //Eat
                }
            }
            if (s == String.Empty) throw new NullReferenceException("值缺失");
            return s;
        }
        public char Skip(char to)
        {
            char c;
            int i = _index;
            do
            {
                c = GetNextChar();
                if (c == 0x00)
                {
                    _index = i;
                    return c;
                }
            } while (c != to);
            _index -= 1;
            return c;
        }
        public void Skip(string to)
        {
            _index = _source.IndexOf(to, _index);
            if (_index < 0)
                _index = _source.Length;
            else
                _index += to.Length;
        }
        public void Unescape()
        {
            _source = Unescape(_source);
        }
        #endregion

        public override string ToString()
        {
            return " at charachter " + _index + " of " + _source;
        }
    }
    public class JSONObject
    {
        private IDictionary<string, object> _mappingTable;

        #region 构造函数
        public JSONObject()
        {
            _mappingTable = new Dictionary<string, object>();
        }
        public JSONObject(IDictionary<string, object> mapping)
        {
            _mappingTable = new Dictionary<string, object>(mapping);
        }
        public JSONObject(string strJSON)
            : this(new JSONTokener(strJSON))
        {
        }
        public JSONObject(JSONTokener tokener)
            : this()
        {
            char c;
            string key;
            if (tokener.GetNextChar() == '%')
                tokener.Unescape();
            tokener.Index -= 1;

            if (tokener.GetNextCharClean() != '{')
                throw new FormatException("A JSONObject must begin with '{'");

            while (true)
            {
                c = tokener.GetNextCharClean();
                switch (c)
                {
                    case (char)0:
                        throw new FormatException("A JSONObject must end with '}'");
                    case '}':
                        return;
                    default:
                        tokener.Index -= 1;
                        key = tokener.GetNextObject().ToString();
                        break;
                }
                if (tokener.GetNextCharClean() != ':')
                    throw new FormatException("Expected a ':' after a key");

                object obj = tokener.GetNextObject();
                _mappingTable.Add(key, obj);
                switch (tokener.GetNextCharClean())
                {
                    case ',':
                        if (tokener.GetNextCharClean() == '}')
                            return;
                        tokener.Index -= 1;
                        break;
                    case '}':
                        return;
                    default:
                        throw new FormatException("Expected a ',' or '}'");
                }
            }
        }
        #endregion

        public struct JSONNull
        {
            public override string ToString()
            {
                return "null";
            }
        }
        public static readonly JSONNull NULL = new JSONNull();

        #region 属性
        public int Count
        {
            get { return _mappingTable.Count; }
        }
        public IDictionary<string, object> MappingTable
        {
            get { return _mappingTable; }
        }
        #endregion

        #region 索引器
        /// <summary>
        /// 通过数值的索引器(只读)
        /// </summary>
        /// <param name="index">序号</param>
        /// <returns>返回值</returns>
        public object this[int index]
        {
            get
            {
                if (index >= _mappingTable.Count) throw new OverflowException("指定索引值超过集合元素数量");
                int counter = 0;
                foreach (KeyValuePair<string, object> pair in _mappingTable)
                {
                    if (counter != index) continue;
                    return pair.Value;
                }
                return null;
            }
        }

        /// <summary>
        /// 通过键对对象集合进行索引,可以设置指定键的值(可读,可写)
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object this[string key]
        {
            get
            {
                if (!_mappingTable.ContainsKey(key)) throw new OverflowException("集合中不存在与指定键对应的值");
                return _mappingTable[key];
            }
            set
            {
                if (value == null) throw new NullReferenceException("不能设置空值");
                if (!_mappingTable.ContainsKey(key)) _mappingTable.Add(key, value);
                else _mappingTable[key] = value;
            }
        }
        #endregion

        #region 获取值的方法

        #region JSONArray
        public JSONArray GetJSONArray(string key)
        {
            object obj = this[key];
            if (!(obj is JSONArray)) throw new FormatException("指定的键值不是JSONArray对象");
            return obj as JSONArray;
        }
        public JSONArray GetJSONArray(int index)
        {
            object obj = this[index];
            if (!(obj is JSONArray)) throw new FormatException("指定的键值不是JSONArray对象");
            return obj as JSONArray;
        }
        #endregion

        #region JSONObject
        public JSONObject GetJSONObject(string key)
        {
            object obj = this[key];
            if (!(obj is JSONObject)) throw new FormatException("指定的键值不是JSONObject对象");
            return obj as JSONObject;
        }
        public JSONObject GetJSONObject(int index)
        {
            object obj = this[index];
            if (!(obj is JSONObject)) throw new FormatException("指定的键值不是JSONObject对象");
            return obj as JSONObject;
        }
        #endregion

        #region GetString
        public string GetString(string key)
        {
            return GetString(key, String.Empty);
        }

        public string GetString(string key, string defaultValue)
        {
            object obj = this[key];
            if (obj != null)
                return obj.ToString();
            return defaultValue;
        }

        public string GetString(int index)
        {
            return GetString(index, String.Empty);
        }

        public string GetString(int index, string defaultValue)
        {
            object obj = this[index];
            if (obj != null)
                return obj.ToString();
            return defaultValue;
        }
        #endregion

        #region GetInt
        public int GetInt(string key)
        {
            return GetInt(key, 0);
        }
        public int GetInt(string key, int defaultValue)
        {
            object obj = this[key];
            if (obj != null)
            {
                if (obj is int)
                    return (int)obj;
                if (obj is string)
                    return Convert.ToInt32(obj);
            }
            return defaultValue;
        }
        public int GetInt(int index)
        {
            return GetInt(index, 0);
        }
        public int GetInt(int index, int defaultValue)
        {
            object obj = this[index];
            if (obj != null)
            {
                if (obj is int)
                    return (int)obj;
                if (obj is string)
                    return Convert.ToInt32(obj);
            }
            return defaultValue;
        }
        #endregion

        #region GetDouble
        public double GetDouble(string key)
        {
            return GetDouble(key, Double.NaN);
        }

        public double GetDouble(string key, double defaultValue)
        {
            object obj = this[key];
            if (obj != null)
            {
                if (obj is double)
                    return (double)obj;
                if (obj is float)
                    return (float)obj;
                if (obj is string)
                    return Convert.ToDouble(obj);
            }
            return defaultValue;
        }

        public double GetDouble(int index)
        {
            return GetDouble(index, Double.NaN);
        }

        public double GetDouble(int index, double defaultValue)
        {
            object obj = this[index];
            if (obj != null)
            {
                if (obj is double)
                    return (double)obj;
                if (obj is float)
                    return (float)obj;
                if (obj is string)
                    return Convert.ToDouble(obj);
            }
            return defaultValue;
        }

        #endregion

        #region GetBoolean
        public bool GetBoolean(string key)
        {
            return GetBoolean(key, false);
        }

        public bool GetBoolean(string key, bool defaultValue)
        {
            object obj = this[key];
            if (obj != null)
            {
                if (obj is bool)
                    return (bool)obj;
                if (obj is string)
                    return Convert.ToBoolean(obj);
            }
            return defaultValue;
        }

        public bool GetBoolean(int index)
        {
            return GetBoolean(index, false);
        }

        public bool GetBoolean(int index, bool defaultValue)
        {
            object obj = this[index];
            if (obj != null)
            {
                if (obj is bool)
                    return (bool)obj;
                if (obj is string)
                    return Convert.ToBoolean(obj);
            }
            return defaultValue;
        }
        #endregion

        #endregion

        #region 其他方法

        public bool ContaintsKey(string key)
        {
            if (String.IsNullOrEmpty(key)) throw new ArgumentNullException("键值不能为空");
            return _mappingTable.ContainsKey(key);
        }
        public bool Containts(KeyValuePair<string, object> item)
        {
            if (item.Key == null || item.Value == null) throw new ArgumentNullException("比照值不能为空");
            return _mappingTable.Contains(item);
        }
        public object Remove(string key)
        {
            if (String.IsNullOrEmpty(key)) throw new ArgumentNullException("键值不能为空");
            if (!_mappingTable.ContainsKey(key)) throw new ArgumentException("指定的键值不存在");

            object obj = this[key];
            _mappingTable.Remove(key);
            return obj;
        }
        #endregion

        public override string ToString()
        {
            object obj = null;
            StringBuilder sb = new StringBuilder();
            sb.Append('{');

            foreach (KeyValuePair<string, object> pair in _mappingTable)
            {
                if (pair.Value != null)
                {
                    sb.Append(JSONUtils.Enquote(pair.Key)).Append(':');
                    //字符串
                    if (pair.Value is string)
                        sb.Append(JSONUtils.Enquote(pair.Value as string));
                    //字节数组
                    else if (pair.Value is byte[])
                        sb.Append(Convert.ToBase64String((byte[])pair.Value));
                    //GUID
                    else if (pair.Value is Guid)
                        sb.Append(JSONUtils.Enquote(pair.Value.ToString()));
                    //JSONArray Or JSONObject
                    else if (pair.Value is JSONArray || pair.Value is JSONObject)
                        sb.Append(obj.ToString());
                    else
                        sb.Append(JSONUtils.Enquote(pair.Value.ToString()));

                    sb.Append(',');
                }
            }
            sb.Remove(sb.Length - 1, 1).Append('}');
            return sb.ToString();
        }

    }
    public class JSONArray
    {
        #region 构造函数
        private IList<object> _list;
        public JSONArray()
        {
            _list = new List<object>();
        }
        public JSONArray(JSONTokener x)
            : this()
        {
            if (x.GetNextCharClean() != '[') throw new FormatException("JSONArray 必须以'['开始");
            if (x.GetNextCharClean() == ']') return;

            x.Index -= 1;
            while (true)
            {
                _list.Add(x.GetNextObject());
                switch (x.GetNextCharClean())
                {
                    case ',':
                        if (x.GetNextCharClean() == ']')
                            return;
                        x.Index -= 1;
                        break;
                    case ']':
                        return;
                    default:
                        throw new FormatException("Expected a ',' or ']'");
                }
            }

        }
        public JSONArray(string s)
            : this(new JSONTokener(s))
        {
        }
        public JSONArray(IEnumerable<object> collection)
        {
            _list = new List<object>(collection);
        }
        #endregion

        #region 索引器和属性
        public int Count
        {
            get { return _list.Count; }
        }
        public object this[int index]
        {
            get
            {
                if (index >= _list.Count) throw new OverflowException("索引超出界限");
                return _list[index];
            }
            set
            {
                if (index >= _list.Count) throw new OverflowException("索引超出界限");
                _list[index] = value;
            }
        }

        public IList<object> List
        {
            get { return _list; }
        }
        #endregion

        #region 公有方法
        public string JoinList(string separator)
        {
            if (_list.Count == 0) return String.Empty;

            StringBuilder sb = new StringBuilder();
            foreach (object obj in _list)
            {
                if (obj != null)
                    sb.Append("");
                else
                {
                    if (obj is string)
                        sb.Append(JSONUtils.Enquote(obj.ToString()));
                    else if (obj is byte[])
                        sb.Append(Convert.ToBase64String((byte[])obj));
                    else if (obj is Guid)
                        sb.Append(JSONUtils.Enquote(obj.ToString()));
                    else if (obj is JSONObject || obj is JSONArray)
                        sb.Append(obj.ToString());
                    else
                        sb.Append(JSONUtils.Enquote(obj.ToString()));

                }
                sb.Append(separator);
            }
            return sb.ToString().TrimEnd(separator.ToCharArray());
        }

        #region 获取值的函数
        public bool GetBoolean(int index, bool defaultValue)
        {
            object obj = this[index];
            if (obj != null)
                return (bool)obj;
            return defaultValue;
        }
        public bool GetBoolean(int index)
        {
            return GetBoolean(index, false);
        }

        public double GetDouble(int index, double defaultValue)
        {
            object obj = this[index];
            if (obj != null)
            {
                if (obj is double)
                    return (double)obj;
                if (obj is float)
                    return (float)obj;
                if (obj is string)
                    return Convert.ToInt32(obj);
            }
            return defaultValue;
        }
        public double GetDouble(int index)
        {
            return GetDouble(index, double.NaN);
        }

        public int GetInt(int index, int defaultValue)
        {
            object obj = this[index];
            if (obj != null)
            {
                if (obj is int)
                    return (int)obj;
                if (obj is string)
                    return Convert.ToInt32(obj);
            }
            return defaultValue;
        }
        public int GetInt(int index)
        {
            return GetInt(index, 0);
        }

        public JSONArray GetJSONArray(int index)
        {
            object obj = this[index];
            if (obj != null)
            {
                if (obj is JSONArray)
                    return (JSONArray)obj;
            }
            return null;
        }

        public JSONObject GetJSONObject(int index)
        {
            object obj = this[index];
            if (obj != null)
            {
                if (obj is JSONObject)
                    return (JSONObject)obj;
            }
            return null;
        }

        public string GetString(int index, string defaultValue)
        {
            object obj = this[index];
            if (obj != null)
                return obj.ToString();
            return defaultValue;
        }
        public string GetString(int index)
        {
            return GetString(index, String.Empty);
        }
        #endregion

        #region 添加值的函数
        public JSONArray Add(object value)
        {
            _list.Add(value);
            return this;
        }
        public JSONArray Add(int index, object value)
        {
            if (index < 0) throw new ArgumentOutOfRangeException("无效的索引值");
            if (value == null) throw new ArgumentNullException("无效的空引用");

            if (index < _list.Count)
                _list.Insert(index, value);
            else
            {
                while (index != _list.Count)
                    _list.Add(null);
                _list.Add(value);
            }
            return this;
        }
        #endregion

        #region 其他函数
        public JSONObject ConvertToJSONObject(JSONArray array)
        {
            if (array == null || array.Count == 0 || this.Count == 0) throw new ArgumentException("输入的JSONArray为空");
            JSONObject jo = new JSONObject();
            int counter = 0;

            foreach (object obj in array.List)
            {
                jo[array.GetString(counter)] = obj;
                ++counter;
            }
            return jo;
        }
        #endregion

        #endregion

        public override string ToString()
        {
            return '[' + JoinList(",") + ']';
        }
    }
}
